use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use thiserror::Error;
use crate::sip_manager::SipConfig;
use crate::audio_manager::AudioConfig;
use ring::aead::{Aad, LessSafeKey, Nonce, UnboundKey, AES_256_GCM};
use ring::rand::{SecureRandom, SystemRandom};
use base64::{Engine as _, engine::general_purpose};
use std::fs;

#[derive(Debug, Error)]
pub enum ConfigManagerError {
    #[error("Configuration error: {0}")]
    ConfigError(String),
    #[error("IO error: {0}")]
    IoError(#[from] std::io::Error),
    #[error("Serialization error: {0}")]
    SerializationError(#[from] serde_json::Error),
    #[error("Encryption error: {0}")]
    EncryptionError(String),
    #[error("Decryption error: {0}")]
    DecryptionError(String),
    #[error("Base64 decode error: {0}")]
    Base64Error(#[from] base64::DecodeError),
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UiConfig {
    pub theme: String,
    pub language: String,
    pub window_width: u32,
    pub window_height: u32,
    pub auto_answer: bool,
}

impl Default for UiConfig {
    fn default() -> Self {
        Self {
            theme: "light".to_string(),
            language: "zh-CN".to_string(),
            window_width: 400,
            window_height: 600,
            auto_answer: false,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AppConfig {
    pub sip: Option<SipConfig>,
    pub audio: AudioConfig,
    pub ui: UiConfig,
}

impl Default for AppConfig {
    fn default() -> Self {
        Self {
            sip: None,
            audio: AudioConfig {
                input_device: None,
                output_device: None,
                input_volume: 1.0,
                output_volume: 1.0,
                echo_cancellation: true,
                noise_suppression: true,
            },
            ui: UiConfig::default(),
        }
    }
}

pub struct ConfigManager {
    config_path: PathBuf,
    key_path: PathBuf,
    rng: SystemRandom,
}

impl ConfigManager {
    pub fn new() -> Result<Self, ConfigManagerError> {
        let config_dir = dirs::config_dir()
            .ok_or_else(|| ConfigManagerError::ConfigError("Could not find config directory".to_string()))?
            .join("tauri-sip-client");

        std::fs::create_dir_all(&config_dir)?;
        
        let config_path = config_dir.join("config.enc");
        let key_path = config_dir.join("key.dat");

        Ok(Self { 
            config_path,
            key_path,
            rng: SystemRandom::new(),
        })
    }

    /// Generate or load encryption key
    fn get_or_create_key(&self) -> Result<Vec<u8>, ConfigManagerError> {
        if self.key_path.exists() {
            let key_data = fs::read(&self.key_path)?;
            if key_data.len() == 32 {
                return Ok(key_data);
            }
        }

        // Generate new key
        let mut key = vec![0u8; 32];
        self.rng.fill(&mut key)
            .map_err(|e| ConfigManagerError::EncryptionError(format!("Failed to generate key: {}", e)))?;
        
        fs::write(&self.key_path, &key)?;
        log::info!("Generated new encryption key");
        
        Ok(key)
    }

    /// Encrypt data using AES-256-GCM
    fn encrypt_data(&self, data: &[u8]) -> Result<Vec<u8>, ConfigManagerError> {
        let key_bytes = self.get_or_create_key()?;
        let unbound_key = UnboundKey::new(&AES_256_GCM, &key_bytes)
            .map_err(|e| ConfigManagerError::EncryptionError(format!("Failed to create key: {}", e)))?;
        let key = LessSafeKey::new(unbound_key);

        let mut nonce_bytes = vec![0u8; 12];
        self.rng.fill(&mut nonce_bytes)
            .map_err(|e| ConfigManagerError::EncryptionError(format!("Failed to generate nonce: {}", e)))?;
        
        let nonce = Nonce::assume_unique_for_key(nonce_bytes.clone().try_into().unwrap());

        let mut in_out = data.to_vec();
        key.seal_in_place_append_tag(nonce, Aad::empty(), &mut in_out)
            .map_err(|e| ConfigManagerError::EncryptionError(format!("Encryption failed: {}", e)))?;

        // Prepend nonce to encrypted data
        let mut result = nonce_bytes;
        result.extend_from_slice(&in_out);
        
        Ok(result)
    }

    /// Decrypt data using AES-256-GCM
    fn decrypt_data(&self, encrypted_data: &[u8]) -> Result<Vec<u8>, ConfigManagerError> {
        if encrypted_data.len() < 12 {
            return Err(ConfigManagerError::DecryptionError("Invalid encrypted data length".to_string()));
        }

        let key_bytes = self.get_or_create_key()?;
        let unbound_key = UnboundKey::new(&AES_256_GCM, &key_bytes)
            .map_err(|e| ConfigManagerError::DecryptionError(format!("Failed to create key: {}", e)))?;
        let key = LessSafeKey::new(unbound_key);

        let (nonce_bytes, ciphertext) = encrypted_data.split_at(12);
        let nonce = Nonce::assume_unique_for_key(nonce_bytes.try_into().unwrap());

        let mut in_out = ciphertext.to_vec();
        let plaintext = key.open_in_place(nonce, Aad::empty(), &mut in_out)
            .map_err(|e| ConfigManagerError::DecryptionError(format!("Decryption failed: {}", e)))?;

        Ok(plaintext.to_vec())
    }

    /// Validate configuration data
    fn validate_config(&self, config: &AppConfig) -> Result<(), ConfigManagerError> {
        // Validate SIP config if present
        if let Some(sip_config) = &config.sip {
            if sip_config.server.is_empty() {
                return Err(ConfigManagerError::ConfigError("SIP server cannot be empty".to_string()));
            }
            if sip_config.username.is_empty() {
                return Err(ConfigManagerError::ConfigError("SIP username cannot be empty".to_string()));
            }
            if sip_config.port == 0 {
                return Err(ConfigManagerError::ConfigError("SIP port cannot be 0".to_string()));
            }
        }

        // Validate audio config
        if config.audio.input_volume < 0.0 || config.audio.input_volume > 2.0 {
            return Err(ConfigManagerError::ConfigError("Invalid input volume range".to_string()));
        }
        if config.audio.output_volume < 0.0 || config.audio.output_volume > 2.0 {
            return Err(ConfigManagerError::ConfigError("Invalid output volume range".to_string()));
        }

        // Validate UI config
        if config.ui.window_width < 300 || config.ui.window_width > 3840 {
            return Err(ConfigManagerError::ConfigError("Invalid window width".to_string()));
        }
        if config.ui.window_height < 400 || config.ui.window_height > 2160 {
            return Err(ConfigManagerError::ConfigError("Invalid window height".to_string()));
        }

        Ok(())
    }

    pub async fn load_config(&self) -> Result<AppConfig, ConfigManagerError> {
        if !self.config_path.exists() {
            let default_config = AppConfig::default();
            self.save_config(&default_config).await?;
            return Ok(default_config);
        }

        let encrypted_data = tokio::fs::read(&self.config_path).await?;
        let decrypted_data = self.decrypt_data(&encrypted_data)?;
        let config_str = String::from_utf8(decrypted_data)
            .map_err(|e| ConfigManagerError::DecryptionError(format!("Invalid UTF-8: {}", e)))?;
        
        let config: AppConfig = serde_json::from_str(&config_str)?;
        self.validate_config(&config)?;
        
        log::info!("Configuration loaded successfully");
        Ok(config)
    }

    pub async fn save_config(&self, config: &AppConfig) -> Result<(), ConfigManagerError> {
        self.validate_config(config)?;
        
        let config_data = serde_json::to_string_pretty(config)?;
        let encrypted_data = self.encrypt_data(config_data.as_bytes())?;
        
        tokio::fs::write(&self.config_path, encrypted_data).await?;
        
        log::info!("Configuration saved securely to: {:?}", self.config_path);
        Ok(())
    }

    pub async fn save_sip_config(&self, sip_config: SipConfig) -> Result<(), ConfigManagerError> {
        let mut config = self.load_config().await?;
        config.sip = Some(sip_config);
        self.save_config(&config).await
    }

    pub async fn save_audio_config(&self, audio_config: AudioConfig) -> Result<(), ConfigManagerError> {
        let mut config = self.load_config().await?;
        config.audio = audio_config;
        self.save_config(&config).await
    }

    pub async fn save_ui_config(&self, ui_config: UiConfig) -> Result<(), ConfigManagerError> {
        let mut config = self.load_config().await?;
        config.ui = ui_config;
        self.save_config(&config).await
    }

    pub async fn clear_sip_config(&self) -> Result<(), ConfigManagerError> {
        let mut config = self.load_config().await?;
        config.sip = None;
        self.save_config(&config).await
    }

    /// Export configuration to base64 string (for backup)
    pub async fn export_config(&self) -> Result<String, ConfigManagerError> {
        let config = self.load_config().await?;
        let config_data = serde_json::to_string(&config)?;
        Ok(general_purpose::STANDARD.encode(config_data))
    }

    /// Import configuration from base64 string (for restore)
    pub async fn import_config(&self, base64_data: &str) -> Result<(), ConfigManagerError> {
        let config_data = general_purpose::STANDARD.decode(base64_data)?;
        let config_str = String::from_utf8(config_data)
            .map_err(|e| ConfigManagerError::ConfigError(format!("Invalid UTF-8: {}", e)))?;
        
        let config: AppConfig = serde_json::from_str(&config_str)?;
        self.validate_config(&config)?;
        self.save_config(&config).await?;
        
        log::info!("Configuration imported successfully");
        Ok(())
    }

    /// Check if configuration file exists
    pub fn config_exists(&self) -> bool {
        self.config_path.exists()
    }

    /// Get configuration file path for debugging
    pub fn get_config_path(&self) -> &PathBuf {
        &self.config_path
    }
}

impl Default for ConfigManager {
    fn default() -> Self {
        Self::new().expect("Failed to create ConfigManager")
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::sip_manager::TransportType;
    use tempfile::TempDir;

    fn create_test_config_manager() -> (ConfigManager, TempDir) {
        let temp_dir = TempDir::new().unwrap();
        let config_path = temp_dir.path().join("config.enc");
        let key_path = temp_dir.path().join("key.dat");
        
        let manager = ConfigManager {
            config_path,
            key_path,
            rng: SystemRandom::new(),
        };
        
        (manager, temp_dir)
    }

    #[tokio::test]
    async fn test_save_and_load_config() {
        let (manager, _temp_dir) = create_test_config_manager();
        
        let mut config = AppConfig::default();
        config.sip = Some(SipConfig {
            server: "sip.example.com".to_string(),
            port: 5060,
            username: "testuser".to_string(),
            password: "testpass".to_string(),
            transport: TransportType::UDP,
            display_name: Some("Test User".to_string()),
            local_port: Some(5061),
        });
        
        // Save config
        manager.save_config(&config).await.unwrap();
        
        // Load config
        let loaded_config = manager.load_config().await.unwrap();
        
        assert_eq!(loaded_config.sip.as_ref().unwrap().server, "sip.example.com");
        assert_eq!(loaded_config.sip.as_ref().unwrap().username, "testuser");
        assert_eq!(loaded_config.sip.as_ref().unwrap().password, "testpass");
    }

    #[tokio::test]
    async fn test_export_import_config() {
        let (manager, _temp_dir) = create_test_config_manager();
        
        let mut config = AppConfig::default();
        config.ui.theme = "dark".to_string();
        config.audio.input_volume = 0.8;
        
        manager.save_config(&config).await.unwrap();
        
        // Export config
        let exported = manager.export_config().await.unwrap();
        
        // Clear config
        let default_config = AppConfig::default();
        manager.save_config(&default_config).await.unwrap();
        
        // Import config
        manager.import_config(&exported).await.unwrap();
        
        // Verify imported config
        let imported_config = manager.load_config().await.unwrap();
        assert_eq!(imported_config.ui.theme, "dark");
        assert_eq!(imported_config.audio.input_volume, 0.8);
    }

    #[tokio::test]
    async fn test_config_validation() {
        let (manager, _temp_dir) = create_test_config_manager();
        
        let mut invalid_config = AppConfig::default();
        invalid_config.sip = Some(SipConfig {
            server: "".to_string(), // Invalid: empty server
            port: 5060,
            username: "testuser".to_string(),
            password: "testpass".to_string(),
            transport: TransportType::UDP,
            display_name: None,
            local_port: None,
        });
        
        let result = manager.save_config(&invalid_config).await;
        assert!(result.is_err());
        assert!(result.unwrap_err().to_string().contains("SIP server cannot be empty"));
    }
}